
package com.mrd.gtimpframe.aspect;


import com.mrd.framework.config.web.json.Result;
import com.mrd.gtimpframe.service.DeclaOperationRecordService;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import bean.result.DeclaResult;

/**
 * 用于记录报关单的业务操作记录
 * 包含如下动作：
 * 客户动作：支付、申请驳回
 * 供应商动作：处理驳回申请、主动海关退单、受理、驳回、广版单一窗口申报、国版单一窗口申报、更新查询跟踪
 * Created by dengdc on 2017/11/16.
 */
@Component
@Aspect
public class LogDeclarationOperation {
    private static Logger logger = LoggerFactory.getLogger(LogDeclarationOperation.class);

    @Autowired
    private DeclaOperationRecordService operationRecordService;

    /**
     * 连接点：用户提交支付时
     * 切入方式：连接点执行前后
     * 动作：记录业务操作记录
     * @param joinPoint 连接点
     * add by dengdc on 2017-11-16
     */
    @Around(value = "execution(* com.mrd.gtimp.order.action.OrderAction.payMent(..))")
    public Object logAfterPayment(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed(); //支付报关费操作结果
        Object[] args = joinPoint.getArgs();
        try {
            if (objIsNotNullAndIsInstanceOfClass(rt, HashMap.class)){
                HashMap result = (HashMap) rt;
                String successFlag = "success";
                String mkey = "payMent";
                if (!successFlag.equals(result.get(mkey))) {
                    //未支付成功不进行记录
                    return rt;
                }
                Object payIdObj = args[0];
                if(!objIsNotNullAndIsInstanceOfClass(payIdObj, String.class)){
                    logger.error("参数类型错误，无法继续登记支付操作记录");
                }
                //保存操作记录
                operationRecordService.savePaymentRecord(payIdObj.toString());
            }
            logger.info("完成支付业务操作记录登记");
        } catch (Exception e){
            e.printStackTrace();
            logger.error("无法完成支付业务操作记录登记，参数:"+ Arrays.toString(args) + ", 异常：" + e.getMessage());
        }
        return rt;
    }

    /**
     * 连接点：用户申请驳回
     * 切入方式：连接点执行完成后
     * 动作：记录业务操作记录
     * @param joinPoint 连接点
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimpframe.action.RejectController.customerApply(..))")
    public Object logAfterCustomerApplyReject(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed(); //申请驳回操作结果
        Object[] args = joinPoint.getArgs();
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, Result.class)){
                Result rs = (Result) rt;
                if(rs.getResult()){
                    Object didObj = args[0];
                    if(!objIsNotNullAndIsInstanceOfClass(didObj, String.class)){
                        logger.error("参数类型错误，无法继续登记【用户驳回申请】操作记录，args:" + Arrays.toString(args));
                    }
                    //保存操作记录
                    operationRecordService.saveCustomerApplyRejectRecord(didObj.toString());
                }
            }
        }catch (Exception e){
            logger.error("无法登记客户操作");
        }
        return rt;
    }

    /**
     * 连接点：供应商处理驳回申请
     * 切入方式：连接点执行完成后
     * 动作：记录业务操作记录
     * @param joinPoint 连接点
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimpframe.action.RejectController.supplierAccept(..))")
    public Object logAfterSupplierAcceptReject(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed(); //正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, Result.class)){
                Result rs = (Result) rt;
                if(rs.getResult()){
                    Object didObj = args[0];
                    if(!objIsNotNullAndIsInstanceOfClass(didObj, String.class)){
                        logger.error("参数类型错误，无法继续登记【供应商处理驳回申请】操作记录，args:" + Arrays.toString(args));
                    }
                    //保存操作记录
                    operationRecordService.saveSupplierAcceptRejectRecord(didObj.toString());
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【供应商处理驳回申请】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }

    /**
     * 连接点：供应商进行海关退单
     * 切入方式：环绕连接点
     * 动作：记录业务操作记录
     * @param joinPoint 连接点
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimpframe.action.RejectController.chargeBack(..))")
    public Object logAfterSupplierChargeBack(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed();//正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, Result.class)){
                Result rs = (Result) rt;
                if(rs.getResult()) {
                    Object didObj = args[0];
                    if (!objIsNotNullAndIsInstanceOfClass(didObj, String.class)) {
                        logger.error("参数类型错误，无法继续登记【供应商海关退单】操作记录，args:" + Arrays.toString(args));
                    }
                    //保存操作记录
                    operationRecordService.saveSupplierChargeBackRecord(didObj.toString());
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【供应商海关退单】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }

    /**
     * 连接点：供应商受理报关单
     * 切入方式：连接点执行前后
     * 动作：记录业务操作记录
     * @param joinPoint 连接点
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimp.business.action.DeclarationAction.doValid(..))")
    public Object logAfterSupplierDoValid(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed();//正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, Result.class)){
                Result rs = (Result) rt;
                if(rs.getResult()) {
                    Object didObj = args[0];
                    if (objIsNotNullAndIsInstanceOfClass(didObj, String.class)) {
                        //保存操作记录
                        operationRecordService.saveSupplierDoValidRecord(didObj.toString());
                    } else {
                        logger.error("参数类型错误，无法继续登记【供应商受理报关单】操作记录，args:" + Arrays.toString(args));
                    }
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【供应商受理报关单】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }

    /**
     * 连接点：线下供应商受理报关单
     * 切入方式：连接点执行前后
     * 动作：记录业务操作记录
     * @param joinPoint 连接点
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimp.business.action.DeclarationAction.doSecondSupValid(..))")
    public Object logAfterSecondSupplierDoValid(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed();//正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, Result.class)){
                Result rs = (Result) rt;
                if(rs.getResult()) {
                    Object didObj = args[0];
                    if (objIsNotNullAndIsInstanceOfClass(didObj, String.class)) {
                        //保存操作记录
                        operationRecordService.saveSecondSupplierDoValidRecord(didObj.toString());
                    } else {
                        logger.error("参数类型错误，无法继续登记【线下供应商受理报关单】操作记录，args:" + Arrays.toString(args));
                    }
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【线下供应商受理报关单】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }

    /**
     * 连接点：供应商处理待审核报关单时驳回
     * 切入方式：连接点执行前后
     * 动作：记录业务操作记录
     * @param joinPoint 连接点
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimp.business.action.DeclarationAction.doReject(..))")
    public Object logAfterSupplierDoReject(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed();//正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, Result.class)){
                Result rs = (Result) rt;
                if(rs.getResult()) {
                    Object didObj = args[0];
                    if (objIsNotNullAndIsInstanceOfClass(didObj, String.class)) {
                       //保存操作记录
                       operationRecordService.saveSupplierDoRejectRecord(didObj.toString());
                    } else {
                        logger.error("参数类型错误，无法继续登记【供应商受理时驳回】操作记录，args:" + Arrays.toString(args));
                    }
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【供应商受理时驳回】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }



    /**
     * 连接点：进行广州单一窗口申报
     * 切入方式：连接点执行完成后
     * 动作：记录业务操作记录
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimp.business.service.cargoDeclaration.component.CargoDeclarationHelper.didUpload(..))")
    public Object logAfterDidGuangZhouSWUpload(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed();//正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, DeclaResult.class)){
                DeclaResult rs = (DeclaResult) rt;
                if(rs.isSuccess()) {
                    Object didObj = args[0];
                    if (objIsNotNullAndIsInstanceOfClass(didObj, String.class)) {
                        //保存操作记录
                        operationRecordService.saveSupplierDidGuangZhouSWUploadRecord(didObj.toString());
                    } else {
                        logger.error("参数类型错误，无法继续登记【广州单一窗口申报】操作记录，args:" + Arrays.toString(args));
                    }
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【广州单一窗口申报】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }

    /**
     * 连接点：进行国家版单一窗口申报
     * 切入方式：连接点执行前后
     * 动作：记录业务操作记录
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimpframe.singlewindow.SingleWindow.up2cargoDecla(..))")
    public Object logAfterCNSWUpload(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed();//正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, DeclaResult.class)){
                DeclaResult rs = (DeclaResult) rt;
                if(rs.isSuccess()) {
                    Object didObj = args[0];
                    if (objIsNotNullAndIsInstanceOfClass(didObj, String.class)) {
                        //保存操作记录
                        operationRecordService.saveSupplierCNSWUploadRecord(didObj.toString());
                    } else {
                        logger.error("参数类型错误，无法继续登记【国家版单一窗口申报】操作记录，args:" + Arrays.toString(args));
                    }
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【国家版单一窗口申报】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }

    /**
     * 连接点：上传到QP小工具
     * 切入方式：连接点执行前后
     * 动作：记录业务操作记录
     * add by dengdc on 2017-11-16
     */
    @Around(value = "execution(* com.mrd.gtimp.business.action.DeclarationAction.syncQPData(..))")
    public Object logAfterSupplierDidQPUpload(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rt = joinPoint.proceed();//正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, DeclaResult.class)){
                DeclaResult rs = (DeclaResult) rt;
                if(rs.isSuccess()) {
                    Object didObj = args[0];
                    if (objIsNotNullAndIsInstanceOfClass(didObj, String.class)) {
                        //保存操作记录
                        operationRecordService.saveSupplierQPUploadRecord(didObj.toString());
                    } else {
                        logger.error("参数类型错误，无法继续登记【上传到QP小工具】操作记录，args:" + Arrays.toString(args));
                    }
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【上传到QP小工具】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }

    /**
     * 连接点：更新查验跟踪记录
     * 切入方式：连接点执行前后
     * 动作：记录业务操作记录
     * add by dengdc on 2017-11-16 
     */
    @Around(value = "execution(* com.mrd.gtimpframe.action.VerifyAction.saveResult(..))")
    public Object logAfterSupplierUpdateVerifyRecord(ProceedingJoinPoint joinPoint)
            throws Throwable {
        Object rt = joinPoint.proceed();//正常执行，连接点执行完后保存操作记录
        Object[] args = joinPoint.getArgs(); //入参
        try {
            if(objIsNotNullAndIsInstanceOfClass(rt, Map.class)){
                Map rs = (HashMap) rt;
                if("0".equals(rs.get("error_code"))) {
                    Object mapObj = args[0];
                    if (objIsNotNullAndIsInstanceOfClass(mapObj, Map.class)) {
                        //保存操作记录
                        operationRecordService.saveSupplierUpdateVerifyRecord((Map) mapObj);
                    } else {
                        logger.error("参数类型错误，无法继续登记【查验跟踪】操作记录，args:" + Arrays.toString(args));
                    }
                }
            }
        }catch (Exception e){
            logger.error("出现错误，无法继续登记【查验跟踪】操作记录，args:" + Arrays.toString(args));
        }
        return rt;
    }


    /**
     * 对象非空，并且是classType的实例
     * @param rt 返回对象
     * @param classType 类型
     * add by dengdc on 2017-11-16 
     */
    private boolean objIsNotNullAndIsInstanceOfClass(Object rt, Class classType){
        return rt != null && classType.isInstance(rt);
    }
}
